/**
 *
 */
package 场景.瞬间高并发请求.redis;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import redis.clients.jedis.Jedis;

/**
 *
 * @Title:通过预生成令牌，只有获取到令牌的用户才可以去数据库操作
 * @author zhoujie
 * @date 2019年1月12日 下午1:51:45
 *
 */
public class Seckill02 {
    static final int MAX_THREAD = 100000;

    static final int Inv = 5;
    static InvDao dto = new InvDao(Inv);// 数据库dao

    static final String tokenkeys = "token:goods:1";

    static CountDownLatch latch = new CountDownLatch(MAX_THREAD);

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(20);
        Jedis redis = new Jedis("127.0.0.1", 6379);
        redis.del("setsucc");
        redis.del(tokenkeys);
        createToken(redis);
        //redis.del("goods:1");//清除用户标记
        for (int i = 0; i < MAX_THREAD; i++) {
            final int id = i;
            Runnable run = () -> doWork(id);// 都是调用doWork方法
            executor.submit(run);
            latch.countDown();
        }
        executor.shutdown();
        while (true) {
            if (executor.isTerminated()) {
                break;
            }
        }
        System.out.println("秒杀结束当前库存：" + dto.getInv());
        System.out.println("数据库总访问次数：" + dto.getCount().intValue());
        System.out.println("抢到商品的用户个数：" + redis.smembers("setsucc").size());
    }

    public static void doWork(int id) {
        Jedis redis = new Jedis("127.0.0.1", 6379);
        try {
            latch.await();// 等线程都就绪后才开始执行
            // 防止重复购买（这里模拟环境其实不会）
            //if (redis.sadd("goods:1", "thread:" + id) == 1) {
            Integer inv = dto.getInv();
            if (inv > 0) {
                String token = redis.spop(tokenkeys);
                //抢到令牌可以去秒杀商品
                if (token != null) {
                    if (dto.outInv(1) > 0) {
                        System.out.println("恭喜你秒杀到商品，用户id:" + id);
                        redis.sadd("setsucc", id + "");
                    } else {
                        System.out.println("商品已经被秒杀完");
                    }
                } else {
                    System.out.println("您没抢到商品，请稍后重试");
                }
            } else {
                System.out.println("商品已经被秒杀完");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            redis.close();
        }

    }

    /**预生成令牌（简单的处理）
     * @param redis
     */
    private static void createToken(Jedis redis) {
        for (int i = 0; i < Inv; i++) {
            redis.sadd(tokenkeys, i + "");
        }
    }
}
